#include "timer.h"
#include <algorithm>
#include <thread>
#include <vector>

CCTimer::CCTimer() : timer_id(-1), event_handler(nullptr), is_callback(false) {
}

CCTimer::~CCTimer() {
    Stop();
}

int CCTimer::Start(int timeout_ms, TimerCallback callback) {
    Stop();
    
    this->callback = callback;
    this->is_callback = true;
    
    CTimerManager& manager = CTimerManager::Instance();
    timer_id = manager.AddTimer(timeout_ms, callback);
    
    return timer_id;
}

int CCTimer::Start(int timeout_ms, TimerOutEvent* event_handler) {
    Stop();
    
    this->event_handler = event_handler;
    this->is_callback = false;
    
    CTimerManager& manager = CTimerManager::Instance();
    timer_id = manager.AddTimer(timeout_ms, event_handler);
    
    return timer_id;
}

int CCTimer::Stop() {
    if (timer_id != -1) {
        CTimerManager& manager = CTimerManager::Instance();
        manager.RemoveTimer(timer_id);
        timer_id = -1;
    }
    return ERR_SUCCESS;
}

int CCTimer::Update(int new_timeout_ms) {
    if (timer_id != -1) {
        CTimerManager& manager = CTimerManager::Instance();
        return manager.UpdateTimer(timer_id, new_timeout_ms);
    }
    return ERR_SOCKET;
}

CTimerManager& CTimerManager::Instance() {
    static CTimerManager instance;
    return instance;
}

int CTimerManager::AddTimer(int timeout_ms, TimerCallback callback) {
    int timer_id = GenerateTimerId();
    
    TimerInfo info;
    info.timer_id = timer_id;
    info.timeout_ms = timeout_ms;
    info.next_timeout = std::chrono::steady_clock::now() + 
                       std::chrono::milliseconds(timeout_ms);
    info.callback = callback;
    info.event_handler = nullptr;
    info.is_callback = true;
    info.recurring = false;
    
    timers[timer_id] = info;
    return timer_id;
}

int CTimerManager::AddTimer(int timeout_ms, TimerOutEvent* event_handler) {
    int timer_id = GenerateTimerId();
    
    TimerInfo info;
    info.timer_id = timer_id;
    info.timeout_ms = timeout_ms;
    info.next_timeout = std::chrono::steady_clock::now() + 
                       std::chrono::milliseconds(timeout_ms);
    info.callback = nullptr;
    info.event_handler = event_handler;
    info.is_callback = false;
    info.recurring = false;
    
    timers[timer_id] = info;
    return timer_id;
}

int CTimerManager::RemoveTimer(int timer_id) {
    auto it = timers.find(timer_id);
    if (it != timers.end()) {
        timers.erase(it);
        return ERR_SUCCESS;
    }
    return ERR_SOCKET;
}

int CTimerManager::UpdateTimer(int timer_id, int new_timeout_ms) {
    auto it = timers.find(timer_id);
    if (it != timers.end()) {
        it->second.timeout_ms = new_timeout_ms;
        it->second.next_timeout = std::chrono::steady_clock::now() + 
                                  std::chrono::milliseconds(new_timeout_ms);
        return ERR_SUCCESS;
    }
    return ERR_SOCKET;
}

void CTimerManager::ProcessTimers() {
    auto now = std::chrono::steady_clock::now();
    std::vector<int> expired_timers;
    
    for (auto it = timers.begin(); it != timers.end(); ++it) {
        int timer_id = it->first;
        TimerInfo& info = it->second;
        if (now >= info.next_timeout) {
            expired_timers.push_back(timer_id);
        }
    }
    
    for (int timer_id : expired_timers) {
        auto it = timers.find(timer_id);
        if (it != timers.end()) {
            TimerInfo& info = it->second;
            
            if (info.is_callback && info.callback) {
                info.callback(timer_id);
            } else if (!info.is_callback && info.event_handler) {
                info.event_handler->ProcessOnTimerOut(timer_id);
            }
            
            // Remove non-recurring timers
            if (!info.recurring) {
                timers.erase(it);
            } else {
                // Update next timeout for recurring timers
                info.next_timeout = std::chrono::steady_clock::now() + 
                                    std::chrono::milliseconds(info.timeout_ms);
            }
        }
    }
}

int CTimerManager::GetNextTimeout() const {
    if (timers.empty()) {
        return -1; // No timers
    }
    
    auto now = std::chrono::steady_clock::now();
    int min_timeout = -1;
    
    for (auto it = timers.begin(); it != timers.end(); ++it) {
        const TimerInfo& info = it->second;
        auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(
            info.next_timeout - now);
        int timeout_ms = static_cast<int>(duration.count());
        
        if (timeout_ms < 0) {
            timeout_ms = 0; // Timer already expired
        }
        
        if (min_timeout == -1 || timeout_ms < min_timeout) {
            min_timeout = timeout_ms;
        }
    }
    
    return min_timeout;
}

int CTimerManager::GenerateTimerId() {
    static int id_counter = 1000; // Start from 1000 to avoid conflicts
    return ++id_counter;
}

CTimerManager* g_timer_manager = &CTimerManager::Instance();